AddCSLuaFile("vgui/tbsduplicator_gui.lua")
require("datastream")
if (CLIENT) then

	language.Add("Tool_tbduplicator_name", "TB's Duplicator")
	language.Add("Tool_tbduplicator_desc", "Duplicate stuff")
	language.Add("Tool_tbduplicator_0", "Right click copy. Left click paste.")
	CreateClientConVar("TBs_dupe_move_to", 1, false, true)
	CreateClientConVar("TBs_dupe_offset_z", 0, false, true)
	CreateClientConVar("TBs_dupe_original_origin", 0, false, true)
	CreateClientConVar("TBs_dupe_paste_constraints", 1, false, true)
	CreateClientConVar("TBs_dupe_show_ghost", 1, false, true)
	CreateClientConVar("TBs_dupe_show_ghost", 1, false, true)
	CreateClientConVar("TBs_dupe_fake_props", 1, false, true)
	CreateClientConVar("TBs_dupe_limit_ghost", 0, false, true)
end
if SERVER then
	Clients = {}
end

TOOL.Category		= "Construction"
TOOL.Name			= "#TB's Duplicator"
TOOL.Command		= nil
TOOL.ConfigName		= nil
TOOL.entities 		= {}
TOOL.constraints 	= {}
TOOL.saveents		= {}
TOOL.saveconstrs	= {}
TOOL.parents 		= {}
TOOL.GhostEntities 	= {}
TOOL.HeadEnt		= nil
TOOL.startpos		= 0
TOOL.busy			= false
TOOL.temptable		= {}
TOOL.pasting 		= false
TOOL.FileToBeWritten= ""
TOOL.FileName		= ""
TOOL.FileToStream	= ""
TOOL.percent		= 0

------------------Server Settings------------------
	if SinglePlayer()then
		TOOL.pasteovertime 	= 0		// How much time for each prop and constraint to spawn, 0 for instant.
	else
		TOOL.pasteovertime 	= 0.2		// How much time for each prop and constraint to spawn, 0 for instant.
	end
TOOL.AllowUpload 	= 1		// Enable/Disable Uploading. 1 = Enable, 0 = Disabled
TOOL.AllowDownload 	= 1		// Enable/Disable Downloading. 1 = Enable, 0 = Disabled

---------------------------------------------------

cleanup.Register( "TBs Duplicator" )


local function TBGenericDuplicatorFunction( Player, data )

	local Entity = ents.Create( data.Class )
	
		if ( !Entity:IsValid() ) then 
		// I think this is a waste of time since you can't do anything with them anyways.
			Player:ChatPrint("DUPLICATOR: Invalid Class, Creating fake prop in its place.")
			Entity = ents.Create( "prop_physics" )
			Entity:SetCollisionGroup( COLLISION_GROUP_WORLD )

		end
		
	duplicator.DoGeneric( Entity, data )
	
	Entity:Spawn()
	Entity:Activate()

	duplicator.DoGenericPhysics( Entity, Player, data )	
	
	table.Add( Entity:GetTable(), data )
	
	return Entity
	
end

local function TBMakePropPhys(Player, Pos, Ang, Model, PhysicsObject, Data)
	Data.Pos = Pos
	Data.Angle = Ang
	Data.Model = Model

	// Make sure this is allowed
	if ( !gamemode.Call( "PlayerSpawnProp", Player, Model ) ) then return nil end
	
	local Prop = ents.Create( "prop_physics" )
		duplicator.DoGeneric( Prop, Data )
		
	Prop:Spawn()
	Prop:Activate()
	
	duplicator.DoGenericPhysics( Prop, Player, Data )
	duplicator.DoFlex( Prop, Data.Flex, Data.FlexScale )
	
	gamemode.Call( "PlayerSpawnedProp", Player, Model, Prop )
	
	return Prop
end

local function TBCreateEntityFromTable(Player, EntTable, Fake)

	local EntityClass = duplicator.FindEntityClass( EntTable.Class )
	
	// This class is unregistered. Instead of failing try using a generic
	// Duplication function to make a new copy..
	if (!EntityClass) then

		return TBGenericDuplicatorFunction( Player, EntTable )
	
	end
		
	// Build the argument list for the Entitie's spawn function
	local ArgList = {}
		
	for iNumber, Key in pairs( EntityClass.Args ) do

		local Arg = nil
	
		// Translate keys from old system
		if ( Key == "pos" || Key == "position" ) then Key = "Pos" end
		if ( Key == "ang" || Key == "Ang" || Key == "angle" ) then Key = "Angle" end
		if ( Key == "model" ) then Key = "Model" end
		
		Arg = EntTable[ Key ]
		
		// Special keys
		if ( Key == "Data" ) then Arg = EntTable end
		
		// If there's a missing argument then unpack will stop sending at that argument
		if ( Arg == nil ) then Arg = false end
		
		ArgList[ iNumber ] = Arg
		
	end
		
	
	// Create and return the entity
	local status, valid
	
	if(EntTable.Class=="prop_physics")then
		valid = TBMakePropPhys(Player, unpack(ArgList)) //Create prop_physics like this because if the model doesn't exist it will cause
														//big problems in the prop_physics spawn function
		
			if(Fake!=1)then // Heres an option to just do away with fake props since you can't do anything with them anyways
			
				if(!valid:GetPhysicsObject():IsValid())then
					valid:Remove()
					return nil
				end
				
			end
	else
	//Create sents using their spawn function with the arguments we stored earlier
		status,valid = pcall(  EntityClass.Func, Player, unpack(ArgList) )

	end
	//If its a valid entity send it back to the entities list so we can constrain it
	if( ValidEntity(valid) )then
		return valid
	else
		return nil
	end
	
end

local function TBCreateConstraintFromTable( Player, Constraint, EntityList, Move, EntTable )
	//Make sure the constraint exists
	local Factory = duplicator.ConstraintType[ Constraint.Type ]

	if ( !Factory ) then return end

		local first=nil //Ent1 or Ent in the constraint's table
		local second=nil //Any other Ent that is not Ent1 or Ent
		local firstindex 
		local secondindex  
		// Build the argument list for the Constraint's spawn function
	local Args = {}

	for k, Key in pairs( Factory.Args ) do

		local Val = Constraint[ Key ]
			
			if( Key == "pl" || Key == "ply" )then
				Val=Player
			end
			
			for i=1, 6 do 

		//	if(!ValidEntity(Constraint.Entity[i])) then Player:ChatPrint("DUPLICATOR: ERROR, Invalid constraints, maybe wrong file version.")return end

			if ( Constraint.Entity and Constraint.Entity[ i ] ) then
	
					if ( Key == "Ent"..i || Key == "Ent" ) then	
					
						if ( Constraint.Entity[ i ].World ) then
							Val = GetWorldEntity()
						else					
							Val = EntityList[ Constraint.Entity[ i ].Index ]
			
								if(!ValidEntity(Val))then
									Player:ChatPrint("DUPLICATOR: ERROR, "..Constraint.Type.." Constraint could not find an entity!")
									return
								else
								
									//Important for perfect duplication
									//Get which entity is which so we can reposition them before constraining
									if(Key== "Ent" || Key == "Ent1")then 
										first=Val
										firstindex = Constraint.Entity[ i ].Index 
									else
										second=Val
										secondindex = Constraint.Entity[ i ].Index 
									end
									
								end
						end
					end
					
					if ( Key == "Bone"..i || Key == "Bone" ) then Val = Constraint.Entity[ i ].Bone end
					if ( Key == "LPos"..i ) then Val = Constraint.Entity[ i ].LPos end
					if ( Key == "WPos"..i ) then Val = Constraint.Entity[ i ].WPos end
					if ( Key == "Length"..i) then Val = Constraint.Entity[ i ].Length end

				end
				
			end
			
				// If there's a missing argument then unpack will stop sending at that argument
	
				if ( Val == nil ) then Val = false end
			
			table.insert( Args, Val )
	
		end
	
	//Also Important for perfect duplications
	//This will move entities in the position they were when they were first constrained. 
	//This enables entities to be duped with out being frozen.
	//It is recorded in the auto run file.
	if(Move)then	
						if(second!=nil and !second:IsWorld() and Constraint.EntityPos!=nil)then
							second:GetPhysicsObject():EnableMotion(false)
							second:SetPos(first:GetPos()-Constraint.EntityPos)
						end
						
						if(first!=nil and Constraint.Ent1Ang!=nil)then
							first:GetPhysicsObject():EnableMotion(false)
							first:SetAngles(Constraint.Ent1Ang)
						end
						
						if(second!=nil and Constraint.Ent2Ang!=nil)then
							second:GetPhysicsObject():EnableMotion(false)
							second:SetAngles(Constraint.Ent2Ang)
						end
						
						if(second !=nil and Constraint.Ent4Ang!=nil)then
							second:GetPhysicsObject():EnableMotion(false)
							second:SetAngles(Constraint.Ent4Ang)
						end
		end
	
	local Entity 
	
	local status, error= pcall(function() Entity= Factory.Func( unpack(Args) ) end)
	if(!status)then Player:ChatPrint("DUPLICATOR: ERROR, Failed to create "..Constraint.Type.." Constraint!") return end
	if(Entity.length)then Entity.length = Constraint["length"] end
		if(first!=nil)then
		first:SetPos(EntTable[firstindex].Pos)
		first:SetAngles(EntTable[firstindex].Angle)
		end
		if(second!=nil)then
		second:SetPos(EntTable[secondindex].Pos)
		second:SetAngles(EntTable[secondindex].Angle)
		end
	return Entity

end

function TBDupePaste(Player, Entities, ConstraintList)

local CreatedEntities = {}
local parents = {}
//Create fake props if their model doesn't exist?
local Fake = tonumber(Player:GetInfo("TBs_dupe_fake_props") or 1)

//Move props into the position they were first constrained in while they are being constrained?
local Move = tonumber(Player:GetInfo("TBs_dupe_move_to") or 1)

	//
	// Create the Entities
	//
	undo.Create("TBs Duplicator")
	for k, v in pairs( Entities ) do
		local entity = TBCreateEntityFromTable( Player, v, Fake ) //Take the entities table we copied and turn it into an actual entity.
		
			if ( entity!=nil ) then
					
			//Freeze it before it is able to move while it is being constrained
		if(tonumber(Player:GetInfo("TBs_dupe_paste_constraints"))==0 and entity:GetPhysicsObject():IsValid()) then 					
			entity:GetPhysicsObject():EnableMotion(false) 
			entity:GetPhysicsObject():Sleep() 
			
		end
				
				CreatedEntities[ k ] = entity	
				CreatedEntities[ k ].BoneMods = table.Copy( v.BoneMods )
				CreatedEntities[ k ].EntityMods = table.Copy( v.EntityMods )
				CreatedEntities[ k ].PhysicsObjects = table.Copy( v.PhysicsObjects )
				CreatedEntities[ k ]:SetCollisionGroup(v.CollisionGroup)
				
				undo.AddEntity(entity)
				Player:AddCleanup("TBs Duplicator", entity)
			end
		
	end
	
	for EntID, Ent in pairs( CreatedEntities ) do	
	//Apply modifiers such as weight, color, or wiremod wiring
		duplicator.ApplyEntityModifiers ( Player, Ent )
		duplicator.ApplyBoneModifiers ( Player, Ent )
		
		
	//If the entity has a PostEntityPaste function tell it to use it now
		if ( Ent.PostEntityPaste ) then
			Ent:PostEntityPaste( Player, Ent, CreatedEntities )
		end
		
		if(Entities[EntID].DupeParentID!=nil)then
			parents[#parents+1] = {Ent = EntID, Parent = Entities[EntID].DupeParentID}
		end
	
	end
		local CreatedConstraints = {}
	if(tonumber(Player:GetInfo("TBs_dupe_paste_constraints"))==1)then
	
	//This is very important, order the constraints by their Identity
	//Their Identity is recorded in the autorun file and is the order in which they were created
	//Since constraints do not have an entity index I had to give them one 
	//This prevents flimsy or saggy constraints
		table.SortByMember(ConstraintList, "Identity", function(a, b) return a > b end)
		
		//
		// Create constraints
		//
		for k, Constraint in pairs( ConstraintList ) do
		//Create the constraint from the constraints table we copied
			local Entity = TBCreateConstraintFromTable( Player, Constraint, CreatedEntities, Move, Entities )
			
				if ( Entity && Entity:IsValid() ) then
					table.insert( CreatedConstraints, Entity )
				end
				
		end
		
		for k,v in pairs(parents)do
				CreatedEntities[v.Ent]:SetParent(CreatedEntities[v.Parent])
		end
			
	end
	
	undo.SetPlayer(Player)
	undo.Finish()
	
	return CreatedEntities, CreatedConstraints
end



local function TBCreateDelayedConstr(ConstraintList, Entities, EntTable, Player, index, delay, Move, parents)

timer.Simple(delay, function()

			local createdent = TBCreateConstraintFromTable( Player, ConstraintList[index], Entities, Move, EntTable )
			ConstraintList[index]=nil

		if(table.Count(ConstraintList)>0)then
			Player:GetTool("tbduplicator"):TBCreateDelayedConstrs(ConstraintList, EntTable, Player, delay, Move, parents)
		else
			local tool = Player:GetTool("tbduplicator")
			undo.Create("TBs Duplicator")	
			for k,v in pairs(tool.temptable)do
				undo.AddEntity(v)
			end
			undo.SetPlayer(Player)
			undo.Finish()
	
			for k,v in pairs(parents)do
				tool.temptable[v.Ent]:SetParent(tool.temptable[v.Parent])
			end
	
			Player:ChatPrint("DUPLICATOR: Finished Spawning")
			tool.temptable = {}
			tool.pasting=false
			tool.busy=false
			tool.startpos = Vector(0,0,25)
			return true
		end
	end)

end

function TOOL:TBCreateDelayedConstrs(ConstraintList, EntTable, Player, delay, Move, parents)

for k, Constraint in pairs( ConstraintList ) do
		//Create the constraint from the constraints table we copied
			local Entity = TBCreateDelayedConstr( ConstraintList, self.temptable, EntTable, Player, k, delay, Move, parents )
			break
		end

end

local function TBCreateDelayedEnt(Entities, ent, ConstraintList, EntTable, Player, index, delay, Fake)

	timer.Simple(delay, function()
local tool = Player:GetTool("tbduplicator")
		local createdent = TBCreateEntityFromTable( Player, ent, Fake )
		
		if ( createdent!=nil ) then
			
			//Freeze it before it is able to move while it is being constrained
					if(createdent:GetPhysicsObject():IsValid()) then 
						createdent:GetPhysicsObject():EnableMotion(false) 
						createdent:GetPhysicsObject():Sleep() 
						/*local v = tool.entities[index]

						if(tool.startpos!=nil)then
							createdent:SetPos(tool.startpos+v.pos)
						else
							createdent:SetPos(ent.Pos)
						end
						
						createdent:SetAngles(v.ang)*/
					end
				

		tool.temptable[index] = createdent
		tool.temptable[index].BoneMods = table.Copy( Entities[index].BoneMods )
		tool.temptable[index].EntityMods = table.Copy( Entities[index].EntityMods )
		tool.temptable[index].PhysicsObjects = table.Copy( Entities[index].PhysicsObjects )
		
		if(table.Count(tool.temptable[index].PhysicsObjects)==1)then
				tool.temptable[index].PhysicsObjects[0].Pos = createdent.pos
		end
		
		tool.temptable[ index ]:SetCollisionGroup(Entities[index].CollisionGroup)
		end
		
		Entities[index]=nil
		if(table.Count(Entities)>0)then
			tool:TBCreateDelayedEnts(Entities, ConstraintList, EntTable, Player, delay, Fake)
		else
			local parents = {}
			for EntID, Ent in pairs( tool.temptable ) do	
			//Apply modifiers such as weight, color, or wiremod wiring
				duplicator.ApplyEntityModifiers ( Player, Ent )
				duplicator.ApplyBoneModifiers ( Player, Ent )
			
			//If the entity has a PostEntityPaste function tell it to use it now
				if ( Ent.PostEntityPaste ) then
					Ent:PostEntityPaste( Player, Ent, tool.temptable )
				end
				
					if(EntTable[EntID].DupeParentID!=nil)then
						parents[#parents+1] = {Ent = EntID, Parent = EntTable[EntID].DupeParentID}
					end

			end
			
			if(table.Count(ConstraintList)>0)then
				tool:TBCreateDelayedConstrs(ConstraintList, EntTable, Player, delay, tonumber(Player:GetInfo("TBs_dupe_move_to") or 1), parents)
			else
			
			undo.Create("TBs Duplicator")	
			for k,v in pairs(tool.temptable)do
				undo.AddEntity(v)
			end
			undo.SetPlayer(Player)
			undo.Finish()
	

	
			Player:ChatPrint("DUPLICATOR: Finished Spawning")
			tool.temptable = {}
			tool.pasting=false
			tool.busy=false
			tool.startpos = Vector(0,0,25)
				
				return true
			end
			
		end
	end)
end

function TOOL:TBCreateDelayedEnts(Entities, ConstraintList, EntTable, Player, delay, Fake)

	for k,v in pairs(Entities)do
		local ent = Entities[k]
		ent.Pos = self.startpos+self.entities[k].pos
			if(table.Count(ent.PhysicsObjects)==1)then
				ent.PhysicsObjects[0].Pos = self.startpos+self.entities[k].pos
			end
			EntTable[k] = ent
		TBCreateDelayedEnt(Entities, ent, ConstraintList, EntTable, Player, k, delay, Fake)
		break
	end
	
end

local function TBDupeDelayedPaste(Player, Entities, ConstraintList, delay)

local CreatedEntities = {}

//Move props into the position they were first constrained in while they are being constrained?


		table.SortByMember(ConstraintList, "Identity", function(a, b) return a > b end)

		local Constraints = {}
		
			if(tonumber(Player:GetInfo("TBs_dupe_paste_constraints"))==1)then
				Constraints = ConstraintList
			end

Player:GetTool("tbduplicator"):TBCreateDelayedEnts(table.Copy(Entities), table.Copy(Constraints), table.Copy(Entities), Player, delay, tonumber(Player:GetInfo("TBs_dupe_fake_props") or 1) )

end

function TOOL:TBMakeGhostFromTable( EntIndex, gParent )

	local EntTable = table.Copy(self.theents[EntIndex])
	local GhostEntity = nil
	
	if(EntTable.Model==nil || !util.IsValidModel(EntTable.Model)) then EntTable.Model="models/error.mdl" end
	
	if ( EntTable.Model:sub( 1, 1 ) == "*" ) then
		GhostEntity = ents.Create( "func_physbox" )
	else
		GhostEntity = ents.Create( "gmod_ghost" )
	end
	
	// If there are too many entities we might not spawn..
	if ( !GhostEntity || GhostEntity == NULL ) then return end
	
	duplicator.DoGeneric( GhostEntity, EntTable )
	
	GhostEntity:Spawn()
	
	GhostEntity:DrawShadow( false )
	GhostEntity:SetMoveType( MOVETYPE_NONE )
	GhostEntity:SetSolid( SOLID_VPHYSICS );
	GhostEntity:SetNotSolid( true )
	GhostEntity:SetRenderMode( RENDERMODE_TRANSALPHA )
	GhostEntity:SetColor( 255, 255, 255, 150 )
	
	GhostEntity.Pos 	= EntTable.Pos
	GhostEntity.Angle 	= self.entities[EntIndex].ang
	

	
	if ( gParent ) then
		GhostEntity:SetParent( self.GhostEntities[gParent] )
	end
	
	// If we're a ragdoll send our bone positions
	if ( EntTable.Class == "prop_ragdoll" ) then

		for k, v in pairs( EntTable.PhysicsObjects ) do
			
			local lPos = v.Pos
			
			// The physics object positions are stored relative to the head entity
			if ( gParent ) then
				lPos = gParent:LocalToWorld( v.LocalPos )
				lPos = GhostEntity:WorldToLocal( v.Pos )
			else
				lPos = lPos + HoldPos
			end
			
			GhostEntity:SetNetworkedBonePosition( k, lPos, v.LocalAngle )
		end	
	
	end
	
	self.GhostEntities[EntIndex] = GhostEntity

	
end

function TOOL:SortGhostTable( Ghosts, gParent)



end

function TOOL:UpdateGhostEntities()

	if ( SERVER && !self.GhostEntities ) then return end
	if ( CLIENT && SinglePlayer() ) then return end
	if ( self.pasting ) then return end
	if ( !self.GhostEntities || table.Count(self.GhostEntities)<=0 ) then return end
	
	local Owner = self:GetOwner()

	local tr = utilx.GetPlayerTrace( Owner, Owner:GetCursorAimVector() )
	local trace = util.TraceLine( tr )
	if (!trace.Hit) then return end
	
	local GhostEnt=nil
	if(ValidEntity(self.GhostEntities[self.HeadEnt]))then
		GhostEnt = self.GhostEntities[self.HeadEnt]
	else
		return
	end
	
	if (!GhostEnt || !GhostEnt:IsValid()) then
		self.GhostEntities = nil
	return end

	GhostEnt:SetMoveType( MOVETYPE_VPHYSICS )
	GhostEnt:SetNotSolid( true )
	
	//local angle  = self:GetOwner():GetAngles()
	//angle.pitch = 0
	//angle.roll = 0
	//angle.yaw = angle.yaw+180
	
	local TargetPos = self.startpos + Vector(0,0,tonumber(self:GetOwner():GetInfo("TBs_dupe_offset_z")))

	local PhysObj = GhostEnt:GetPhysicsObject()
	if ( PhysObj && PhysObj:IsValid() ) then
	
		PhysObj:EnableMotion( false )
		PhysObj:SetPos( TargetPos + trace.HitPos )
		PhysObj:SetAngle( GhostEnt.Angle  )
		PhysObj:Wake()
		
	else
	
		// Give the head ghost entity a physics object
		// This way the movement will be predicted on the client
		if ( CLIENT ) then
			GhostEnt:PhysicsInit( SOLID_VPHYSICS )
		end
	
	end
		
end

function TOOL:LeftClick( trace )

		if CLIENT then return true end
		if self.busy then self:GetOwner():ChatPrint("DUPLICATOR: Tool is busy...") return false end
		if table.Count(self.entities)<=0 then return false end

	local Owner = self:GetOwner()
	self.busy=true
	self.pasting = true
	Owner:ChatPrint("DUPLICATOR: Spawning...")
	local pos = nil
	//Find which prop is at the bottom so the contraption doesn't spawn mostly underground
	
	for k,v in pairs(self.entities)do
		
			if pos == nil then
				pos= v.pos.z
			end
			
			if pos>v.pos.z then
				pos= v.pos.z
			end
		end
		
			pos = Vector(0,0,1)*math.abs(pos)
			

	local startpos = trace.HitPos + pos + Vector(0,0,25) + Vector(0,0,tonumber(Owner:GetInfo("TBs_dupe_offset_z")))

		if(tonumber(Owner:GetInfo("TBs_dupe_original_origin"))==1)then
			startpos=nil
		end

	self.startpos = startpos
	

	
	local Ents, Const
	
	//Create our entities and constraints
		if(self.pasteovertime==0)then
				if(startpos!=nil)then
					for k,v in pairs(self.entities)do
						self.theents[k].Pos = startpos+v.pos
						if(table.Count(self.theents[k].PhysicsObjects)==1)then
								self.theents[k].PhysicsObjects[0].Pos = startpos+v.pos
						end
					end
				end
			Ents, Const = TBDupePaste(Owner, table.Copy(self.theents), table.Copy(self.constraints))
		else
			TBDupeDelayedPaste(Owner, table.Copy(self.theents), table.Copy(self.constraints), self.pasteovertime)
			return true
		end
		
	Owner:ChatPrint("DUPLICATOR: Finished Spawning")
	self.temptable = {}
	self.pasting=false
	self.busy=false
	self.startpos = Vector(0,0,25)
	
	return true
end

	local function checkit(ply)
		local tool = ply:GetTool("tbduplicator")
		for k,v in pairs(tool.constraints)do
			v.Constraint= nil
		end
	end
	
	concommand.Add("Constrs", checkit)
	
local function CreateConstraintTable(Constraints)
	local ConstraintTables = {}
	
	for k,v in pairs(Constraints)do
			local Constraint = {}
			if(v!=nil && v.Constraint)then
				Constraint.Entity={}
				v.Constraint = nil
				v.OnDieFunctions=nil
				local Type = duplicator.ConstraintType[ v.Type ]
				
				
				if ( Type ) then 

						for k, key in pairs( Type.Args ) do
							local Val = v[ key ]
							
							
							local found = false
							
							
							
								for i=1, 6 do 
								
									if ( v.Entity[ i ] ) then							
												
										if ( key == "Bone"..i ) then Val = v.Entity[ i ].Bone found=true end
										
										if ( key == "Length"..i ) then Val = v.Entity[ i ].Length found=true end
										
										if ( key == "LPos"..i ) then Val = v.Entity[ i ].LPos found=true end
										
										if ( key == "WPos"..i ) then Val = v.Entity[ i ].WPos found=true end
										
										if ( key=="Ent"..i ) then found = true v[ key ]=nil end
									end
								end
								
								if ( Val == nil ) then Val = false end
				
								if !found and (key != "Ent") and (key != "Bone") then
									Constraint[key]=Val
									v[ key ]=nil
								end
								
						end
				
						
						if(v["Ent"] && IsValid(v["Ent"]))then
								Constraint.Entity[ 1 ] = {}
								Constraint.Entity[ 1 ].Index = v["Ent"]:EntIndex()
						else
							for i=1,6 do
								if(v["Ent"..i] && IsValid(v["Ent"..i]))then
									Constraint.Entity[ i ] = {}
									Constraint.Entity[ i ].Index = v["Ent"..i]:EntIndex()
								end
							end	
						end
						
						for o,p in pairs(v.Entity)do

								Constraint.Entity[ o ] = {}
								Constraint.Entity[ o ].Index	 	= p[ "Index" ]
								Constraint.Entity[ o ].Bone 		= p[ "Bone" ]
								Constraint.Entity[ o ].WPos 		= p[ "WPos" ]
								Constraint.Entity[ o ].Length 		= p[ "Length" ]
								Constraint.Entity[ o ].LPos 		= p[ "LPos" ]
								Constraint.Entity[ o ].World		= p[ "World" ]
							
							for i=1 ,6 do
								Constraint.Entity[ o ]["Bone"..i] 		= p[ "Bone"..i ]
								Constraint.Entity[ o ]["WPos"..i]		= p[ "WPos"..i ]
								Constraint.Entity[ o ]["Length"..i] 	= p[ "Length"..i ]
								Constraint.Entity[ o ]["LPos"..i] 		= p[ "LPos"..i ]			
							end
									
						end
						
					
						
				end		
					v.Entity=nil
					for o,p in pairs(v)do
						if(p!=nil)then
							Constraint[o]=p
						end
					end
			end
		table.insert(ConstraintTables, Constraint)
	end
	
	return ConstraintTables 
end	
	
function TOOL:RightClick( trace )

		if (!trace.Entity ||
			!trace.Entity:IsValid() ||
			trace.Entity:IsPlayer() )
		then
		
			return true
	
		end

		if CLIENT then return true end
		if self.busy then self:GetOwner():ChatPrint("DUPLICATOR: Tool is busy...") return true end
	self:ReleaseGhostEntity()
			// Copy the entities and constraints
			trace.Entity:GetPhysicsObject():EnableMotion(false)
	self.startpos = trace.Entity:GetPos()
	self.entities={}
	self.constraints={}
	self.GhostEntities={}
	
	local gParent = trace.Entity:EntIndex()
	self.HeadEnt = trace.Entity:EntIndex()

	debug.sethook() //prevent infinite loop

	self.theents, self.constraints = duplicator.Copy(trace.Entity) //copy the entitie's and constraint's tables
	self.theents = table.Copy(self.theents)
	//self.constraints = table.Copy(self.constraints)
	self.constraints = CreateConstraintTable(table.Copy(self.constraints))

		self.entities[gParent] = { pos=self.theents[gParent].Entity:GetPos()-self.startpos , ang=self.theents[gParent].Entity:GetAngles()}

	if(tonumber(self:GetOwner():GetInfo("TBs_dupe_show_ghost"))==1)then self:TBMakeGhostFromTable( gParent ) end
	
	//Create a local position between the props and the prop that was clicked and record its angle
		for k,x in pairs(self.theents)do
		
			if(x.Entity:GetPhysicsObject():IsValid())then
				x.Entity:GetPhysicsObject():EnableMotion(false)
			end
			
		if( k!=gParent )then
			if( x.Entity:GetParent() and IsValid(x.Entity:GetParent()) ) then
				self.theents[x.Entity:EntIndex()].DupeParentID = x.Entity:GetParent():EntIndex()
			end
		
			self.entities[x.Entity:EntIndex()] = { pos=x.Entity:GetPos()-self.startpos , ang=x.Entity:GetAngles()}
			
				if(tonumber(self:GetOwner():GetInfo("TBs_dupe_show_ghost"))==1)then
					if(tonumber(self:GetOwner():GetInfo("TBs_dupe_limit_ghost"))==1)then
					local divis = k/3
						if(divis-math.floor(divis)==0)then
							self:TBMakeGhostFromTable( x.Entity:EntIndex(), gParent ) 
						end
					else
						self:TBMakeGhostFromTable( x.Entity:EntIndex(), gParent ) 
					end	
				end
			end
			
		end
		
		local pos = nil
	//Find which prop is at the bottom so the contraption doesn't spawn mostly underground
		for k,v in pairs(self.entities)do
		
			if pos == nil then
				pos= v.pos.z
			end
			
			if pos>v.pos.z then
				pos= v.pos.z
			end
		end
		
	pos = Vector(0,0,1)*math.abs(pos)

	self.startpos = pos + Vector(0,0,25) 

	//This is very important, order the constraints by their Identity
	//Their Identity is recorded in the autorun file and is the order in which they were created
	//Since constraints do not have an entity index I had to give them one 
	//This prevents flimsy or saggy constraints
		table.SortByMember(self.constraints, "Identity", function(a, b) return a > b end)
	
	return true	
end

function TOOL:Reload( trace )
	return false	
end

function TOOL:Deploy()

if ( CLIENT ) then return end

self:ReleaseGhostEntity()

	if(table.Count(self.entities)>0)then 
		self.GhostEntities={}
		if(tonumber(self:GetOwner():GetInfo("TBs_dupe_show_ghost"))==1)then 
			self:TBMakeGhostFromTable( self.HeadEnt ) 
			for k,v in pairs(self.theents)do
				if(k!=self.HeadEnt)then
				
					if(tonumber(self:GetOwner():GetInfo("TBs_dupe_show_ghost"))==1)then
						if(tonumber(self:GetOwner():GetInfo("TBs_dupe_limit_ghost"))==1)then
						local divis = k/3
							if(divis-math.floor(divis)==0)then
								self:TBMakeGhostFromTable( k, self.HeadEnt ) 
							end
						else
							self:TBMakeGhostFromTable( k, self.HeadEnt ) 
						end	
					end
					//self:TBMakeGhostFromTable( k, self.HeadEnt )
				end
			end
		end 
	end

end

function TOOL:Think()

	self:UpdateGhostEntities()
	
end

//Figure out which folder to use if the Steam ID is unavailable
local function GetFilePath(ply)
	local path = string.gsub(ply:SteamID(),":","_")

		if path == "UNKNOWN" then
			path = ply:Name()
		end
	
	return path
end

//Check that there isn't a file named the same and find a name that will work
local function namecheck (name, directory)

	if(file.Exists(directory..name..".txt"))then
		local ending = string.Explode("",name)
	
			if(ending[string.len(name)-1]=="_" and tonumber(ending[string.len(name)])!=nil) then
				local num = tonumber(ending[string.len(name)])
				num = num+1
				name = string.Left(name, string.len(name)-1)
				name=name..num
				return namecheck(name, directory)
			else
				name=name.."_1"
				return namecheck(name, directory)
			end
		
	else
		return name
	end
	
end

//Search a table and find and delete any functions because glon will not write them
//The only thing this really affects is seat animations
local function PurgeFunctions(data)

		for k,v in pairs(data)do
		
			if(type(v)=="function" and type(v)!="table")then
				data[k]=nil
			else
				data[k]=v
			end
			
			if(type(v)=="table")then
				data[k] = PurgeFunctions(v)
			end
			
		end
	
	return data
end

/*
local function SaveConstraint(ply, Constraint, Constrs, Index)

local v =  Constrs[Index]

			if(v!=nil && v.Constraint)then
				Constraint[Index]={}	
				Constraint[Index].Entity={}
				v.Constraint = nil
				v.OnDieFunctions=nil
				local Type = duplicator.ConstraintType[ v.Type ]
				
				
				if ( Type ) then 

						for k, key in pairs( Type.Args ) do
							local Val = v[ key ]
							
							
						local found = false
							
								for i=1, 6 do 
								
									if ( v.Entity[ i ] ) then							
										
										if ( key == "Bone"..i ) then Val = v.Entity[ i ].Bone found=true end
										
										if ( key == "Length"..i ) then Val = v.Entity[ i ].Length found=true end
										
										if ( key == "LPos"..i ) then Val = v.Entity[ i ].LPos found=true end
										
										if ( key == "WPos"..i ) then Val = v.Entity[ i ].WPos found=true end
										
										if ( key=="Ent"..i ) then found = true v[ key ]=nil end
									end
								end
								
								if ( Val == nil ) then Val = false end
				
								if !found and (key != "Ent") and (key != "Bone") then
									Constraint[Index][key]=Val
									v[ key ]=nil
								end
								
						end
				
						
						for o,p in pairs(v.Entity)do

								Constraint[Index].Entity[ o ] = {}
								Constraint[Index].Entity[ o ].Index	 	= p[ "Index" ]
								Constraint[Index].Entity[ o ].Bone 		= p[ "Bone" ]
								Constraint[Index].Entity[ o ].WPos 		= p[ "WPos" ]
								Constraint[Index].Entity[ o ].Length 	= p[ "Length" ]
								Constraint[Index].Entity[ o ].LPos 		= p[ "LPos" ]
								Constraint[Index].Entity[ o ].World		= p[ "World" ]
							
							for i=1 ,6 do
								Constraint[Index].Entity[ o ]["Bone"..i] 		= p[ "Bone"..i ]
								Constraint[Index].Entity[ o ]["WPos"..i]		= p[ "WPos"..i ]
								Constraint[Index].Entity[ o ]["Length"..i] 		= p[ "Length"..i ]
								Constraint[Index].Entity[ o ]["LPos"..i] 		= p[ "LPos"..i ]			
							end
									
						end
						
					
						
					end		
					v.Entity=nil
					for o,p in pairs(v)do
						if(p!=nil)then
							Constraint[Index][o]=p
						end
					end
					PrintTable(Constraint)
			end

		Constrs[Index]=nil
		ply:ConCommand("tbdupe_setpercent "..ply:GetTool("tbduplicator").percent)
		ply:GetTool("tbduplicator"):SetUpConstraints(ply, Constraint, Constrs)

end*/

local function WriteFile(ply)
	
	local tool = ply:GetTool("tbduplicator")
	
	local write = "[Entity]"..glon.encode(tool.saveents).."[/Entity] "
	write = write.."[Info]"..glon.encode(tool.entities).."[/Info] "
	write = write.."[Constraints]"..glon.encode(tool.saveconstrs).."[/Constraints]"
	local path = GetFilePath(ply)
	local name = namecheck(tool.FileName, "tbsduplicator/"..path..tool.FilePath.."/")

	file.Write("tbsduplicator/"..path..tool.FilePath.."/"..name..".txt", write)
		if(file.Exists("tbsduplicator/"..path..tool.FilePath.."/"..name..".txt") )then
			umsg.Start("tbdupe_addfile", ply)
				umsg.String(name)
			umsg.End()
			ply:ChatPrint("DUPLICATOR: File was successfully saved.")
		else
			ply:ChatPrint("DUPLICATOR: ERROR, Save was unsuccessful!")
		end
		ply:ConCommand("tbdupe_RemoveProgressBar")
		tool.saveents={}
		tool.saveconstrs={}
		tool.FileName=""
		tool.FilePath=""
		tool.percent = 0
end
/*
function TOOL:SetUpConstraints(ply, Constraint, Constrs)
	local tool = ply:GetTool("tbduplicator")
	if(table.Count(Constrs)>0)then

		for k,v in pairs(Constrs)do

			timer.Simple(0.05, SaveConstraint, ply, table.Copy(Constraint), Constrs, k)
			break
		end
	else
		timer.Simple(1, function() 
			tool.saveconstrs = PurgeFunctions(table.Copy(Constraint)) 
			WriteFile(ply)
		end)
	end

end
*/

local function SaveEntity(ply, Entity, Ents, Index)

	local tool = ply:GetTool("tbduplicator")

local v = tool.theents[Index]

local class = duplicator.FindEntityClass(v.Class)

			Entity[Index]={Class=v.Class, Skin=v.Skin, Model = v.Model, EntityMods=v.EntityMods, BoneMods=v.BoneMods, PhysicsObjects=v.PhysicsObjects, DupeParentID=v.DupeParentID, CollisionGroup=v.CollisionGroup}
			
				if(class)then
				
					for j,m in pairs(class.Args)do
						local temp = m
						
							if ( m == "pos" || m == "position" ) then temp = "Pos" end
							
							if (m == "ang" || m == "Ang" || m == "angle" ) then temp = "Angle" end
			
							if ( m == "model" ) then temp = "Model" end
			
						Entity[Index][temp]= v[temp]

					end
				end
			
			Ents[Index]=nil
			ply:ConCommand("tbdupe_setpercent "..tool.percent)
			tool:SetUpEntities(ply, Entity, Ents)
end

function TOOL:SetUpEntities(ply, Entity, Ents)
	local tool = ply:GetTool("tbduplicator")
	if(table.Count(Ents)>0)then
		for k,v in pairs(Ents)do
			timer.Simple(0.05, SaveEntity, ply, Entity, Ents, k)
			break
		end
	else
		timer.Simple(1, function() 
			tool.saveents = PurgeFunctions(table.Copy(Entity)) 
			tool.saveconstrs = PurgeFunctions(table.Copy(tool.constraints)) 
			WriteFile(ply)
			//tool:SetUpConstraints(ply, {}, table.Copy(tool.constraints))
		end)
	end

end

local function SaveDuplication(ply, cmd, args)

	local tool = ply:GetTool( "tbduplicator" )

			if (!tool) then return end
			if tool.busy then ply:ChatPrint("DUPLICATOR: Tool is busy...") return end
			//tool.busy = true
			
	if(table.Count(tool.theents)<=0) then return end
	tool.FileName = args[1]
	tool.FilePath = args[2]
	ply:ConCommand("tbdupe_StartProgressBar")
	tool.percent = math.floor(100/(table.Count(tool.theents)))

	tool:SetUpEntities(ply, {}, table.Copy(tool.theents))

end

local function ClearTool(ply)
local tool = ply:GetTool("tbduplicator")
tool.theents={} 
tool.entities={} 
tool.constraints={} 
//tool.busy=false
end

function OpenDuplication(ply, cmd, args)

	local tool = ply:GetTool( "tbduplicator" )
	
			if (!tool) then return end
			if tool.busy then ply:ChatPrint("DUPLICATOR: Tool is busy...") return end
			//tool.busy = true
			
			tool:ReleaseGhostEntity()
			
	local path = GetFilePath(ply)
	local decode = file.Read("tbsduplicator/"..path..args[1])

			if decode==nil then tool.busy=false return end
				local beginning = string.find(decode, "[Entity]",1, true)

					if(beginning==nil)then ply:ChatPrint("DUPLICATOR: ERROR, file is corrupt!") return end
					
				beginning= beginning+8
				local ending = string.find(decode, "[/Entity]",1, true)

					if(ending==nil)then ply:ChatPrint("DUPLICATOR: ERROR, file is corrupt!") return end
					
				ending= ending-1
				local status, error= pcall(function() tool.theents = glon.decode(string.sub(decode, beginning, ending)) end)
				if(!status) then ply:ChatPrint("DUPLICATOR: ERROR, could not decode file!") ClearTool(ply) return end
				
				beginning = string.find(decode, "[Info]",1, true)

					if(beginning==nil)then ply:ChatPrint("DUPLICATOR: ERROR, file is corrupt!") ClearTool(ply) return  end
				
				beginning= beginning+6
				ending = string.find(decode, "[/Info]",1, true)
		
					if(ending==nil)then ply:ChatPrint("DUPLICATOR: ERROR, file is corrupt!") ClearTool(ply) return end
				
				ending= ending-1
				local status, error= pcall(function() tool.entities = glon.decode(string.sub(decode, beginning, ending)) end)
				if(!status) then ply:ChatPrint("DUPLICATOR: ERROR, could not decode file!") ClearTool(ply) return end
				
				beginning = string.find(decode, "[Constraints]",1, true)

					if(beginning==nil)then ply:ChatPrint("DUPLICATOR: ERROR, file is corrupt!") ClearTool(ply) return end
				
				beginning= beginning+13
				ending = string.find(decode, "[/Constraints]",1, true)

					if(ending==nil)then ply:ChatPrint("DUPLICATOR: ERROR, file is corrupt!") ClearTool(ply) return end

				ending= ending-1
				local status, error= pcall(function() tool.constraints = glon.decode(string.sub(decode, beginning, ending)) end)
				if(!status) then ply:ChatPrint("DUPLICATOR: ERROR, could not decode file!") ClearTool(ply) return end
				
				if(tonumber(tool:GetOwner():GetInfo("TBs_dupe_show_ghost"))==1)then
					tool.GhostEntities={}
					local pos = nil
					
					for k,v in pairs(tool.entities)do
					
						if( v.pos==Vector(0,0,0) )then
							tool.HeadEnt=k
							tool:TBMakeGhostFromTable( k ) 
						end
						
						if pos == nil then
							pos= v.pos.z
						end
				
						if pos>v.pos.z then
							pos= v.pos.z
						end
						
					end
					
					pos = Vector(0,0,1)*math.abs(pos)

					tool.startpos = pos + Vector(0,0,25)
					
						for k,v in pairs(tool.theents)do
							if( k!=tool.HeadEnt )then			
								if(tonumber(tool:GetOwner():GetInfo("TBs_dupe_show_ghost"))==1)then
									if(tonumber(tool:GetOwner():GetInfo("TBs_dupe_limit_ghost"))==1)then
									local divis = k/3
										if(divis-math.floor(divis)==0)then
											tool:TBMakeGhostFromTable( k, tool.HeadEnt ) 
										end
									else
										tool:TBMakeGhostFromTable( k, tool.HeadEnt ) 
									end	
								end
								//tool:TBMakeGhostFromTable( k, tool.HeadEnt) 
							end
						end
				end

				ply:ChatPrint("DUPLICATOR: File opened successfully.")
				//tool.busy = false
end

local function DoPopulation(ply, cmd, args)

	local path = GetFilePath(ply)
	local folder = file.IsDir("tbsduplicator/"..path..args[1])

	local files = {}
	local folders = {}
		if folder then
			files = file.Find("tbsduplicator/"..path..args[1].."/*.txt")
			folders = file.FindDir("tbsduplicator/"..path..args[1].."/*")
		end

	umsg.Start("tbdupe_clearfiles", ply)
	umsg.End()
	
	if("tbsduplicator/"..path!="tbsduplicator/"..path..args[1])then
			umsg.Start("tbdupe_addfiles", ply)
			umsg.String([[\..]])
			umsg.End()
	end
	
		for k,v in pairs(folders)do
			umsg.Start("tbdupe_addfiles", ply)
			umsg.String( "/"..v.."/.." )
			umsg.End()
		end
	
		for k,v in pairs(files)do
			umsg.Start("tbdupe_addfiles", ply)
			umsg.String( string.gsub(v,".txt","") )
			umsg.End()
		end
		
end

local function DoDeleteFile(ply, cmd, args)
	local path = GetFilePath(ply)
	file.Delete("tbsduplicator/"..path..args[2].."/"..args[1]..".txt")
end


			//======================================
			//		Recieve File From Client
			//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

local function PermissionToRecieveFile(ply, cmd, args)
	
	local tool = ply:GetTool("tbduplicator")
	if !tool then return end
	if tool.busy then ply:ChatPrint("DUPLICATOR: Tool is busy...") return end
	
	if(tool.AllowUpload==0)then
		ply:ChatPrint("DUPLICATOR: Uploading Has Been Disabled.")
		return
	end
	
	for k,v in pairs(Clients)do
		if(v==ply)then
			ply:ChatPrint("DUPLICATOR: Tool is busy...")
			return
		end
	 end
	 table.insert(Clients, ply)
	umsg.Start("tbdupe_beginupload",ply)
		umsg.Short(100)
	umsg.End()
	//call client upload start

end

local function SaveFile(ply, command, args)
	local path = GetFilePath(ply)
	local name = namecheck(ply:GetTool("tbduplicator").FileName, "tbsduplicator/"..path.."/")
	local status, error = pcall(function() file.Write("tbsduplicator/"..path.."/"..name..".txt", ply:GetTool("tbduplicator").FileToBeWritten) end)
	ply:GetTool("tbduplicator").FileToBeWritten = ""
	ply:GetTool("tbduplicator").busy = false
		if(status==false)then
			ply:ChatPrint("DUPLICATOR: ERROR, File was unable to be uploaded!")
		else
			umsg.Start("tbdupe_addfiles", ply)
			umsg.String( name )
			umsg.End()
		end
		//table.remove(Clients, ply)
		for k,v in pairs(Clients)do
			if(v==ply)then
				Clients[k]=nil
			end
		end
		
	ply:GetTool("tbduplicator").busy=false
end

local function RecieveFile(ply, cmd, args)

	ply:GetTool("tbduplicator").FileToBeWritten = ply:GetTool("tbduplicator").FileToBeWritten..args[1]

	if(args[5]!=nil)then
		ply:GetTool("tbduplicator").FileName = args[5]
	end
	
		if(tonumber(args[3])==tonumber(args[4]))then
			SaveFile(ply)
			
		else
			local ending = args[3] + 1
			local start = args[2] + 1
			umsg.Start("tbdupe_streamuploaddata", ply)
				umsg.Short(start)
				umsg.Short(ending)
				umsg.Short(tonumber(args[4]))
				umsg.Short(100)
			umsg.End()
		end
//Tell Client we're ready for the next part
end

			//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			//======================================


			//======================================
			//			Send File To Client
			//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

local function InitializeFile(ply, cmd, args)

	local tool = ply:GetTool("tbduplicator")
	if !tool then return end
	if tool.busy then ply:ChatPrint("DUPLICATOR: Tool is busy...") return end
	
	if(tool.AllowDownload==0)then
		ply:ChatPrint("DUPLICATOR: Downloading Has Been Disabled.")
		return
	end
	
	/*if(!file.Exists(args[1]..".txt"))then
		ply:ChatPrint("DUPLICATOR: File Doesn't Exist")
		return
	end*/
	
	for k,v in pairs(Clients)do
		if(v==ply)then
			ply:ChatPrint("DUPLICATOR: Tool is busy...")
			return
		end
	 end
	 table.insert(Clients, ply)
local path = GetFilePath(ply)

		tool.FileToStream = file.Read("tbsduplicator/"..path.."/"..args[1]..".txt")
		
		local maxparts = math.ceil(string.len(tool.FileToStream)/100)
	 ply:ConCommand("tbdupe_DownloadAccepted "..maxparts.." "..args[1])
end

local function SendFile(ply, cmd, args)

	timer.Simple( 0.1, function()
	
		local maxparts = args[1]
		local start = args[2]
		local ending = args[3]

		local tool = ply:GetTool("tbduplicator")

		local strlength = string.len(tool.FileToStream)

		local ending2=nil
			if(ending*100>strlength)then
				ending2=strlength
			else
				ending2=ending*100
			end


		local data = string.sub(tool.FileToStream, (start*100)+1, ending2)
		
		

		umsg.Start("tbdupe_streamdownloaddata", ply)
			umsg.Short(start)
			umsg.Short(ending)
			umsg.Short(maxparts)
			umsg.String(data)
		umsg.End()

			if(ending==maxparts)then
				tool.FileToStream=""
				tool.busy=false
				for k,v in pairs(Clients)do
					if(v==ply)then
						Clients[k]=nil
					end
				end
			end
	end)


end

			//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			//======================================

			
local function foldercheck (name, directory)

	if(file.IsDir(directory..name))then
		local ending = string.Explode("",name)
	
			if(ending[string.len(name)-1]=="_" and tonumber(ending[string.len(name)])!=nil) then
				local num = tonumber(ending[string.len(name)])
				num = num+1
				name = string.Left(name, string.len(name)-1)
				name=name..num
				return namecheck(name, directory)
			else
				name=name.."_1"
				return namecheck(name, directory)
			end
		
	else
		return name
	end
	
end
				
			local function CreateNewFolder(ply, command, args)
				local path = GetFilePath(ply)
				local name = foldercheck(args[1], "tbsduplicator/"..path..args[2].."/")
				file.CreateDir("tbsduplicator/"..path..args[2].."/"..name)
				
				if(file.IsDir("tbsduplicator/"..path..args[2].."/"..name))then
					umsg.Start("tbdupe_addfiles", ply)
						umsg.String( "/"..name.."/.." )
					umsg.End()
				end	
			end
			

	if SERVER then

		concommand.Add("tbdupe_DownloadFile", DoDownloadFile)
		
		concommand.Add("tbdupe_NewFolder", CreateNewFolder)
		concommand.Add("tbdupe_SendFile", SendFile)
		concommand.Add("tbdupe_InitializeFile", InitializeFile)
		concommand.Add("tbdupe_SaveDuplication", SaveDuplication) 
		concommand.Add("tbdupe_OpenDuplication", OpenDuplication) 
		concommand.Add("tbdupe_DoPopulation", DoPopulation) 
		concommand.Add("tbdupe_DoDeleteFile", DoDeleteFile) 
		concommand.Add("tbdupe_DownloadFile2",PermissionToRecieveFile)
		concommand.Add("tbdupe_DownloadFile3",RecieveFile)
		

	end


	if CLIENT then
		local DuplicatorControl = nil
		local pnldef_Duplicator = vgui.RegisterFile( "vgui/tbsduplicator_gui.lua" )

			function TOOL.BuildCPanel(panel123)
	
				panel123:AddControl("Header", {
					Text = "TB's Duplicator",
					Description = "Duplicate stuff."
				})
		
				DuplicatorControl = vgui.CreateFromTable( pnldef_Duplicator )
				panel123:AddPanel( DuplicatorControl )
				DuplicatorControl:Populate("")
				panel123:AddControl( "CheckBox", { Label = "Move to Constraining Position", Command = "TBs_dupe_move_to" })
				panel123:AddControl( "Slider", { Label = "Add or subtract Z", Command = "TBs_dupe_offset_z", min = -500, max = 500 })
				panel123:AddControl( "CheckBox", { Label = "Paste at original origin", Command = "TBs_dupe_original_origin" })
				panel123:AddControl( "CheckBox", { Label = "Paste with constraints", Command = "TBs_dupe_paste_constraints" })
				panel123:AddControl( "CheckBox", { Label = "Create Ghost", Command = "TBs_dupe_show_ghost" })
				panel123:AddControl( "CheckBox", { Label = "Create invalid props as fake", Command = "TBs_dupe_fake_props" })
				panel123:AddControl( "CheckBox", { Label = "Reduce the amount of ghost", Command = "TBs_dupe_limit_ghost" })
			end
	
			local function Clearfiles( m )
				DuplicatorControl.List:Clear()	
			end
		
			local function Updatefiles( m )
				DuplicatorControl.List:AddLine(m:ReadString())
			end
		
			local function Addfile( m )
				DuplicatorControl.List:AddLine(m:ReadString())
				DuplicatorControl.List:SortByColumn(1)
			end
		
		
			//======================================
			//				Progress Bar
			//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
			local percent = 0
			
			local function ProgressBar()
				draw.RoundedBox( 10, ScrW()/2-52, ScrH()/2-14, 104, 28, Color( 61, 61, 61, 150 ) )
					
					if(percent>=20) then
						draw.RoundedBox( 10, ScrW()/2-50, ScrH()/2-12, percent, 24, Color( 10, 255, 10, 150 ) )
					else
						draw.RoundedBox( 10, ScrW()/2-50, ScrH()/2-12, 20, 24, Color( 10, 255, 10, 150 ) )
					end

				draw.SimpleText(percent.."%", "ScoreboardText", ScrW() / 2, ScrH()/2, Color(255,255,255,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
			end

			local function SetPercentage(amt)
				percent = amt
			end
			local function SetPercentage2(ply, command, args)

				percent = percent + args[1]
			end
			concommand.Add("tbdupe_setpercent", SetPercentage2)

			local function StartProgressBar()
				hook.Add("HUDPaint", "TBsProgressBar", ProgressBar)
			end
			concommand.Add("tbdupe_StartProgressBar", StartProgressBar)

			local function RemoveProgressBar()
				hook.Remove("HUDPaint", "TBsProgressBar")
				percent=0
			end	
			concommand.Add("tbdupe_RemoveProgressBar", RemoveProgressBar)
			
			//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			//======================================
		
		
			//======================================
			//		Download File From Server
			//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
		local FileName = ""
		local FileToBeWritten = ""
		
		
			local function SaveFile()

				file.Write("tbsduplicator/"..LocalPlayer():Name().."/"..FileName..".txt", FileToBeWritten)
					//if(file.Exists(panel.FileName..".txt"))then

					//end
					RemoveProgressBar()
					SetPercentage(0)
					FileName=""
					FileToBeWritten=""
			end
		
		
			local function test(um)
				local start = um:ReadShort()
				local ending = um:ReadShort()
				local maxparts = um:ReadShort()
				local data = um:ReadString()
				FileToBeWritten = FileToBeWritten..data
				SetPercentage(math.ceil((ending/maxparts)*100))
					if(ending==maxparts)then
						SaveFile()
					//	ply:ConCommand("tbdupe_finishstream")
					else
						start = start + 1
						ending = ending + 1
						RunConsoleCommand("tbdupe_SendFile", maxparts, start, ending)
					end
			end
			
		local function namecheck (name, directory)
	
			if(file.Exists(directory..name..".txt"))then
				local ending = string.Explode("",name)
					if(ending[string.len(name)-1]=="_" and tonumber(ending[string.len(name)])!=nil) then
						local num = tonumber(ending[string.len(name)])
						num = num+1
						name = string.Left(name, string.len(name)-1)
						name=name..num
						return namecheck(name, directory)
					else
						name=name.."_1"
						return namecheck(name, directory)
					end
			else
				return name
			end
		end

		local function StartDownload(ply, command, args)

				if(args[2]!=nil)then
					FileName = namecheck(args[2], "tbsduplicator/"..LocalPlayer():Name().."/")
				end
			StartProgressBar()
			SetPercentage(0)
			RunConsoleCommand("tbdupe_SendFile", args[1], 0, 1)
		end
		
			//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			//======================================
			
			
			//======================================
			//		  Upload File To Server
			//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
			
			local FileToStream = ""
			
			
			local function StreamUpload(start, ending, maxparts, maxbytes, name)
			
				timer.Simple( 0.1, function()

					SetPercentage(math.ceil((start/maxparts)*100))
					local strlength = string.len(FileToStream)

					local ending2=nil
						if(ending*maxbytes>strlength)then
							ending2=strlength
						else
							ending2=ending*maxbytes
						end

					local data = string.sub(FileToStream, (start*maxbytes)+1, ending2)

					RunConsoleCommand("tbdupe_DownloadFile3", data, start, ending, maxparts, name )
						if(ending==maxparts)then
							FileToStream=""
							RemoveProgressBar()
						end
				end)
			
			end	
			
			
			local function InitializeUpload(um)
			
				if DuplicatorControl.List2:GetSelected()[1]!=nil then
					
					local path = DuplicatorControl.Path

					if(file.Exists(path))then

							FileToStream = file.Read(path)
							local txtfile = DuplicatorControl.List2:GetSelected()[1]:GetValue(1)
							local bytes = um:ReadShort()
							local max = math.ceil(string.len(FileToStream)/bytes)
							StartProgressBar()
							StreamUpload(0, 1, max, bytes, txtfile)
					end
				end		
			end

			
			local function UploadData(um)
			
				local start	 	= um:ReadShort()
				local ending 	= um:ReadShort()
				local maxparts 	= um:ReadShort()
				local maxbytes 	= um:ReadShort()
				local name 		= um:ReadString()
			
				StreamUpload(start, ending, maxparts, maxbytes)
			end
			
			//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			//======================================
			
		concommand.Add("tbdupe_DownloadAccepted", StartDownload)
		
		usermessage.Hook("tbdupe_streamuploaddata", UploadData)
		usermessage.Hook("tbdupe_beginupload", InitializeUpload)
		usermessage.Hook("tbdupe_streamdownloaddata", test)
		usermessage.Hook( "tbdupe_addfile", Addfile )
		usermessage.Hook( "tbdupe_addfiles", Updatefiles )
		usermessage.Hook( "tbdupe_clearfiles", Clearfiles )
	end